﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using RaisingStudio.SmallProgram.Library.Internal;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Shapes;

namespace RaisingStudio.SmallProgram.Library
{
    [SmallProgramType]
    public static class GraphicsWindow
    {
        internal static SolidColorBrush _backgroundBrush;
        internal static Grid _container;
        internal static CoreDispatcher _dispatcher;
        internal static SolidColorBrush _fillBrush;
        internal static FontFamily _fontFamily;
        private static string _fontName = "Segoe UI";
        internal static double _fontSize = 12.0;
        internal static FontStyle _fontStyle = FontStyles.Normal;
        internal static FontWeight _fontWeight = FontWeights.Bold;
        private static double _height = 480.0;
        private static Image _imageElement;
        internal static bool _isLeftMouseButtonDown;
        internal static bool _isRightMouseButtonDown;
        public static Control _keyboardControl;
        private static Key _lastKey;
        private static Border _mainBorder;
        private static StackPanel _mainPanel;
        private static double _mouseX;
        private static double _mouseY;
        internal static Dictionary<Primitive, UIElement> _objectsMap = new Dictionary<Primitive, UIElement>();
        internal static Pen _pen;
        private static double _penThickness;
        private static Random _random;
        internal static Canvas _shapesCanvas;
        private static TextBlock _titleBlock;
        private static double _width = 640.0;
        private static WriteableBitmap _writeableBitmap;
        private static DispatcherTimer bitmapInvalidateTimer;
        private static int invalidates = 0;


        public static Primitive BackgroundColor
        {
            get
            {
                return (string)InvokeWithReturn(delegate
                {
                    return _backgroundBrush.Color.ToString();
                });
            }
            set
            {
                BeginInvoke(delegate
                {
                    _backgroundBrush = new SolidColorBrush(ColorConverter.GetColor((string)value));
                    _mainBorder.Background = _backgroundBrush;
                });
            }
        }

        public static Primitive BrushColor
        {
            get
            {
                return (string)InvokeWithReturn(delegate
                {
                    return _fillBrush.Color.ToString();
                });
            }
            set
            {
                BeginInvoke(delegate
                {
                    _fillBrush = new SolidColorBrush(ColorConverter.GetColor((string)value));
                });
            }
        }

        public static Primitive CanResize
        {
            get
            {
                return 0;
            }
            set
            {
            }
        }

        public static Panel Element
        {
            get
            {
                return _mainPanel;
            }
        }

        public static Primitive FontBold
        {
            get
            {
                return (_fontWeight.Weight == FontWeights.Bold.Weight);
            }
            set
            {
                if (value != 0)
                {
                    _fontWeight = FontWeights.Bold;
                }
                else
                {
                    _fontWeight = FontWeights.Normal;
                }
            }
        }

        public static Primitive FontItalic
        {
            get
            {
                return (_fontStyle == FontStyles.Italic);
            }
            set
            {
                if (value != 0)
                {
                    _fontStyle = FontStyles.Italic;
                }
                else
                {
                    _fontStyle = FontStyles.Normal;
                }
            }
        }

        public static Primitive FontName
        {
            get
            {
                return _fontName;
            }
            set
            {
                _fontName = (string)value;
                BeginInvoke(delegate
                {
                    _fontFamily = new FontFamily { Source = _fontName };
                });
            }
        }

        public static Primitive FontSize
        {
            get
            {
                return _fontSize;
            }
            set
            {
                _fontSize = (double)value.GetAsDecimal();
            }
        }

        public static Primitive Height
        {
            get
            {
                return _height;
            }
            set
            {
                _height = (double)value;
                BeginInvoke(delegate
                {
                    _mainBorder.Height = _height;
                    _mainBorder.Clip = new RectangleGeometry { Rect = new Rect(0.0, 0.0, (double)Width, (double)value) };
                });
            }
        }

        public static Primitive LastKey
        {
            get
            {
                if (_lastKey == Key.Enter)
                {
                    return "Return";
                }
                if (_lastKey == Key.Ctrl)
                {
                    return "LeftCtrl";
                }
                return _lastKey.ToString();
            }
        }

        public static Primitive LastText
        {
            get
            {
                return LastKey;
            }
        }

        public static Primitive Left
        {
            get
            {
                return 0;
            }
            set
            {
            }
        }

        public static Primitive MouseX
        {
            get
            {
                return _mouseX;
            }
        }

        public static Primitive MouseY
        {
            get
            {
                return _mouseY;
            }
        }

        public static Primitive PenColor
        {
            get
            {
                return (string)InvokeWithReturn(delegate
                {
                    return _pen.Brush.Color.ToString();
                });
            }
            set
            {
                BeginInvoke(delegate
                {
                    _pen.Brush = new SolidColorBrush(ColorConverter.GetColor((string)value));
                });
            }
        }

        public static Primitive PenWidth
        {
            get
            {
                return _penThickness;
            }
            set
            {
                _penThickness = (double)value;
                BeginInvoke(delegate
                {
                    _pen.Thickness = _penThickness;
                });
            }
        }

        public static Primitive Title
        {
            get
            {
                return (string)InvokeWithReturn(delegate
                {
                    return _titleBlock.Text;
                });
            }
            set
            {
                BeginInvoke(delegate
                {
                    _titleBlock.Text = (string)value;
                });
            }
        }

        public static Primitive Top
        {
            get
            {
                return 0;
            }
            set
            {
            }
        }

        public static Primitive Width
        {
            get
            {
                return _width;
            }
            set
            {
                _width = (double)value;
                BeginInvoke(delegate
                {
                    _mainBorder.Width = _width;
                    _mainBorder.Clip = new RectangleGeometry { Rect = new Rect(0.0, 0.0, (double)value, (double)Height) };
                });
            }
        }
        

        private static event SmallProgramCallback _keyDown;
        public static event SmallProgramCallback KeyDown
        {
            add
            {
                _keyDown = null;
                _keyDown += value;
            }
            remove
            {
                _keyDown -= value;
            }
        }

        private static event SmallProgramCallback _keyUp;
        public static event SmallProgramCallback KeyUp
        {
            add
            {
                _keyUp = null;
                _keyUp += value;
            }
            remove
            {
                _keyUp -= value;
            }
        }

        private static event SmallProgramCallback _mouseDown;
        public static event SmallProgramCallback MouseDown
        {
            add
            {
                _mouseDown = null;
                _mouseDown += value;
            }
            remove
            {
                _mouseDown -= value;
            }
        }

        private static event SmallProgramCallback _mouseMove;
        public static event SmallProgramCallback MouseMove
        {
            add
            {
                _mouseMove = null;
                _mouseMove += value;
            }
            remove
            {
                _mouseMove -= value;
            }
        }

        private static event SmallProgramCallback _mouseUp;
        public static event SmallProgramCallback MouseUp
        {
            add
            {
                _mouseUp = null;
                _mouseUp += value;
            }
            remove
            {
                _mouseUp -= value;
            }
        }

        private static event SmallProgramCallback _textInput;
        public static event SmallProgramCallback TextInput
        {
            add
            {
                _textInput = null;
                _textInput += value;
            }
            remove
            {
                _textInput -= value;
            }
        }


        public static void Initialize()
        {
            _mainPanel = new StackPanel();
            TextBlock block = new TextBlock();
            block.Text = "Small Program";
            block.FontFamily = new FontFamily { Source = _fontName };
            block.FontSize = 14.0;
            block.FontWeight = FontWeights.Bold;
            _titleBlock = block;
            Canvas canvas = new Canvas();
            canvas.Background = new SolidColorBrush(Colors.Transparent);
            _shapesCanvas = canvas;
            _writeableBitmap = new WriteableBitmap(0x400, 0x300);
            Border border = new Border();
            border.BorderThickness = new Thickness { Left = 2.0, Top = 2.0, Right = 2.0, Bottom = 2.0 };
            border.BorderBrush = new SolidColorBrush(new Color { A = 0xff, R = 0x66, G = 0x66, B = 0x66 });
            border.HorizontalAlignment = HorizontalAlignment.Left;
            border.Width = _width;
            border.Height = _height;
            RectangleGeometry geometry = new RectangleGeometry();
            geometry.Rect = new Rect(0.0, 0.0, _width, _height);
            border.Clip = geometry;
            _mainBorder = border;
            _container = new Grid();
            Image image = new Image();
            image.Source = _writeableBitmap;
            image.Stretch = Stretch.None;
            _imageElement = image;
            _container.Children.Add(_imageElement);
            _container.Children.Add(_shapesCanvas);
            _keyboardControl = new ContentControl();
            _container.Children.Add(_keyboardControl);
            _mainBorder.Child = _container;
            _mainPanel.Children.Add(_titleBlock);
            _mainPanel.Children.Add(_mainBorder);
            _dispatcher = _mainPanel.Dispatcher;
            _penThickness = 2.0;
            Pen pen = new Pen();
            pen.Brush = new SolidColorBrush(Colors.Black);
            pen.Thickness = _penThickness;
            _pen = pen;
            _fillBrush = new SolidColorBrush(new Color { A = 0xff, R = 0x88, G = 0xAA, B = 0xcc });
            _backgroundBrush = new SolidColorBrush(Colors.White);
            _fontFamily = new FontFamily { Source = _fontName };
            _fontStyle = FontStyles.Normal;
            _fontWeight = FontWeights.Bold;
            SignupForWindowEvents();
            SmallProgramApplication.Initialize();
        }


        internal static void AddControl(string name, Control control)
        {
            control.Foreground = _fillBrush;
            control.FontFamily = _fontFamily;
            control.FontStyle = _fontStyle;
            control.FontSize = _fontSize;
            control.FontWeight = _fontWeight;
            AddShape(name, control);
        }

        internal static void AddShape(string name, FrameworkElement shape)
        {
            _objectsMap[name] = shape;
            BeginInvoke(delegate
            {
                shape.Name = name;
                _shapesCanvas.Children.Add(shape);
            });
        }

        internal static void BeginInvoke(InvokeHelper invokeDelegate)
        {
            SmallProgramApplication.BeginInvoke(invokeDelegate);
        }

        public static void Clear()
        {
            BeginInvoke(delegate
            {
                _shapesCanvas.Children.Clear();
                _writeableBitmap = new WriteableBitmap(0x400, 0x300);
                _imageElement.Source = _writeableBitmap;
            });
        }

        internal static bool ContainsShape(string shapeName)
        {
            return _objectsMap.ContainsKey(shapeName);
        }

        internal static void DoubleAnimateProperty(UIElement element, DependencyProperty property, double end, int duration)
        {
            double d = (double)element.GetValue(property);
            if (double.IsNaN(d))
            {
                d = 0.0;
            }
            DoubleAnimation animation = new DoubleAnimation();
            animation.From = new double?(d);
            animation.To = new double?(end);
            animation.Duration = new Duration { TimeSpan = TimeSpan.FromMilliseconds((double)duration), Type = DurationType.TimeSpan };
            animation.FillBehavior = FillBehavior.HoldEnd;
            DoubleAnimation timeline = animation;
            // TODO: Animation
            //element.BeginAnimation(property, timeline);
        }

        public static void DrawBoundText(Primitive x, Primitive y, Primitive width, Primitive text)
        {
            BeginInvoke(delegate
            {
                TextBlock element = new TextBlock
                {
                    Text = text,
                    Foreground = _fillBrush,
                    FontSize = _fontSize,
                    FontFamily = _fontFamily,
                    FontStyle = _fontStyle,
                    FontWeight = _fontWeight,
                    Width = (double)width,
                    TextWrapping = TextWrapping.Wrap
                };
                // TODO:
                //_writeableBitmap.Render(element, new TranslateTransform { X = (double)x, Y = (double)y });
                InvalidateBitmap();
            });
        }

        public static void DrawEllipse(Primitive left, Primitive top, Primitive width, Primitive height)
        {
            BeginInvoke(delegate
            {
                DrawShape(new Ellipse { Width = (double)width, Height = (double)height }, (double)left, (double)top);
            });
        }

        public static void DrawImage(Primitive imageName, Primitive x, Primitive y)
        {
            if (!imageName.IsEmpty)
            {
                BeginInvoke(delegate
                {
                    BitmapSource bitmap = ImageList.GetBitmap(imageName);
                    if (bitmap != null)
                    {
                        Image ic = new Image
                        {
                            Source = bitmap
                        };
                        BitmapImage image = bitmap as BitmapImage;
                        if (image != null)
                        {
                            image.ImageOpened += delegate(object o, RoutedEventArgs e)
                                {
                                    // TODO:
                                    //_writeableBitmap.Render(ic, new TranslateTransform { X = (double)x, Y = (double)y });
                                    InvalidateBitmap();
                                };
                        }
                        // TODO:
                        //_writeableBitmap.Render(ic, new TranslateTransform { X = (double)x, Y = (double)y });
                        InvalidateBitmap();
                    }
                });
            }
        }

        public static void DrawLine(Primitive x1, Primitive y1, Primitive x2, Primitive y2)
        {
            BeginInvoke(delegate
            {
                DrawShape(new Line { X1 = (double)x1, Y1 = (double)y1, X2 = (double)x2, Y2 = (double)y2 }, 0.0, 0.0);
            });
        }

        public static void DrawRectangle(Primitive left, Primitive top, Primitive width, Primitive height)
        {
            BeginInvoke(delegate
            {
                DrawShape(new Rectangle { Width = (double)width, Height = (double)height }, (double)left, (double)top);
            });
        }

        public static void DrawResizedImage(Primitive imageName, Primitive x, Primitive y, Primitive width, Primitive height)
        {
            InvokeHelper invokeDelegate = null;
            BitmapSource image;
            if (!imageName.IsEmpty)
            {
                image = ImageList.GetBitmap(imageName);
                if (image != null)
                {
                    if (invokeDelegate == null)
                    {
                        invokeDelegate = delegate
                        {
                            Image ic = new Image
                            {
                                Source = image,
                                Width = (double)width,
                                Height = (double)height
                            };
                            BitmapImage bitmapImage = image as BitmapImage;
                            if (bitmapImage != null)
                            {
                                bitmapImage.ImageOpened += delegate(object o, RoutedEventArgs e)
                                    {
                                        // TODO:
                                        //_writeableBitmap.Render(ic, new TranslateTransform { X = (double)x, Y = (double)y });
                                        InvalidateBitmap();
                                    };
                            }
                            // TODO:
                            //_writeableBitmap.Render(ic, new TranslateTransform { X = (double)x, Y = (double)y });
                            InvalidateBitmap();
                        };
                    }
                    BeginInvoke(invokeDelegate);
                }
            }
        }

        private static void DrawShape(Shape shape, double left, double top)
        {
            shape.Stroke = _pen.Brush;
            shape.StrokeThickness = _pen.Thickness;
            TranslateTransform transform = new TranslateTransform();
            transform.X = left;
            transform.Y = top;
            // TODO:
            //_writeableBitmap.Render(shape, transform);
            InvalidateBitmap();
        }

        public static void DrawText(Primitive x, Primitive y, Primitive text)
        {
            BeginInvoke(delegate
            {
                TextBlock element = new TextBlock
                {
                    Text = text,
                    Foreground = _fillBrush,
                    FontSize = _fontSize,
                    FontFamily = _fontFamily,
                    FontStyle = _fontStyle,
                    FontWeight = _fontWeight
                };
                // TODO:
                //_writeableBitmap.Render(element, new TranslateTransform { X = (double)x, Y = (double)y });
                InvalidateBitmap();
            });
        }

        public static void DrawTriangle(Primitive x1, Primitive y1, Primitive x2, Primitive y2, Primitive x3, Primitive y3)
        {
            BeginInvoke(delegate
            {
                DrawShape(new Polygon { Points = { new Point((double)x1, (double)y1), new Point((double)x2, (double)y2), new Point((double)x3, (double)y3) } }, 0.0, 0.0);
            });
        }

        public static void FillEllipse(Primitive left, Primitive top, Primitive width, Primitive height)
        {
            BeginInvoke(delegate
            {
                FillShape(new Ellipse { Width = (double)width, Height = (double)height }, (double)left, (double)top);
            });
        }

        public static void FillRectangle(Primitive left, Primitive top, Primitive width, Primitive height)
        {
            BeginInvoke(delegate
            {
                FillShape(new Rectangle { Width = (double)width, Height = (double)height }, (double)left, (double)top);
            });
        }

        private static void FillShape(Shape shape, double left, double top)
        {
            shape.Fill = _fillBrush;
            TranslateTransform transform = new TranslateTransform();
            transform.X = left;
            transform.Y = top;
            // TODO:
            //_writeableBitmap.Render(shape, transform);
            InvalidateBitmap();
        }

        public static void FillTriangle(Primitive x1, Primitive y1, Primitive x2, Primitive y2, Primitive x3, Primitive y3)
        {
            BeginInvoke(delegate
            {
                FillShape(new Polygon { Points = { new Point((double)x1, (double)y1), new Point((double)x2, (double)y2), new Point((double)x3, (double)y3) } }, 0.0, 0.0);
            });
        }

        public static Primitive GetColorFromRGB(Primitive red, Primitive green, Primitive blue)
        {
            int num = System.Math.Abs((int)(red % 0x100));
            int num2 = System.Math.Abs((int)(green % 0x100));
            int num3 = System.Math.Abs((int)(blue % 0x100));
            return string.Format("#{0:X2}{1:X2}{2:X2}", num, num2, num3);
        }

        public static Primitive GetRandomColor()
        {
            if (_random == null)
            {
                _random = new Random((int)DateTime.Now.Ticks);
            }
            return string.Format("#{0:X2}{1:X2}{2:X2}", _random.Next(0x100), _random.Next(0x100), _random.Next(0x100));
        }

        internal static void VerifyAccess()
        {
        }

        public static void Show()
        {
        }

        public static void Hide()
        {
        }

        private static void InvalidateBitmap()
        {
            if (bitmapInvalidateTimer == null)
            {
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromMilliseconds(20.0);
                bitmapInvalidateTimer = timer;
                bitmapInvalidateTimer.Stop();
                bitmapInvalidateTimer.Tick += delegate(object o, object e)
                {
                    _writeableBitmap.Invalidate();
                    bitmapInvalidateTimer.Stop();
                };
            }
            invalidates++;
            if (invalidates > 10)
            {
                _writeableBitmap.Invalidate();
                invalidates = 0;
                bitmapInvalidateTimer.Stop();
            }
            else
            {
                bitmapInvalidateTimer.Stop();
                bitmapInvalidateTimer.Start();
            }
        }

        internal static void Invoke(InvokeHelper invokeDelegate)
        {
            SmallProgramApplication.Invoke(invokeDelegate);
        }

        internal static object InvokeWithReturn(InvokeHelperWithReturn invokeDelegate)
        {
            return SmallProgramApplication.InvokeWithReturn(invokeDelegate);
        }

        internal static void RemoveShape(Primitive name)
        {
            InvokeHelper invokeDelegate = null;
            UIElement shape = null;
            if (_objectsMap.TryGetValue(name, out shape))
            {
                _objectsMap.Remove(name);
                if (invokeDelegate == null)
                {
                    invokeDelegate = delegate
                    {
                        _shapesCanvas.Children.Remove(shape);
                    };
                }
                BeginInvoke(invokeDelegate);
            }
        }

        //internal static void SetCursor(Cursor cursor)
        //{
        //    BeginInvoke(delegate
        //    {
        //        _mainPanel.Cursor = cursor;
        //    });
        //}

        public static void SetPixel(Primitive x, Primitive y, Primitive color)
        {
            BeginInvoke(delegate
            {
                bool primitive = x < _writeableBitmap.PixelWidth;
                if (primitive)
                {
                    if (primitive & (y < _writeableBitmap.PixelHeight))
                    {
                        Color color1 = ColorConverter.GetColor((string)color);
                        // TODO:
                        //_writeableBitmap.Pixels[(int)((y * _writeableBitmap.PixelWidth) + x)] = (((color1.A << 0x18) | (color1.R << 0x10)) | (color1.G << 8)) | color1.B;
                        _writeableBitmap.Invalidate();
                    }
                }
            });
        }

        public static Primitive GetPixel(Primitive x, Primitive y)
        {
            return (string)InvokeWithReturn(delegate
            {
                bool primitive = x < _writeableBitmap.PixelWidth;
                if (primitive)
                {
                    if (primitive & (y < _writeableBitmap.PixelHeight))
                    {
                        int num = 0;
                        // TODO:
                        //num = _writeableBitmap.Pixels[(int)((y * _writeableBitmap.PixelWidth) + x)];
                        return new Color { A = (byte)(num >> 0x18), R = (byte)((num >> 0x10) & 0xff), G = (byte)((num >> 8) & 0xff), B = (byte)(num & 0xff) }.ToString();
                    }
                    return "Transparent";
                }
                return null;
            });
        }


        public static void ShowMessage(Primitive message, Primitive title)
        {
            // TODO:
            /*
            if (SmallProgramApplication.Dispatcher.CheckAccess())
            {
                SmallProgramApplication.InvokeInMainThread(delegate
                {
                    ShowMessage(message, title);
                });
            }
            else
            {
                ManualResetEvent resetEvent = new ManualResetEvent(false);
                BeginInvoke(delegate
                {
                    MessageBoxHelper.ShowMessageBox(_container, (string)message, (string)title, resetEvent);
                });
                resetEvent.WaitOne();
            }
             */
        }

        private static void SignupForWindowEvents()
        {
            // TODO:
            /*
            _shapesCanvas.MouseLeftButtonDown += delegate
            {
                _isLeftMouseButtonDown = true;
                _keyboardControl.Focus();
                _shapesCanvas.CaptureMouse();
                SmallProgramCallback callback = _mouseDown;
                if (callback != null)
                {
                    callback();
                }
            };
            _shapesCanvas.MouseLeftButtonUp += delegate
            {
                _shapesCanvas.ReleaseMouseCapture();
                _isLeftMouseButtonDown = false;
                SmallProgramCallback callback = _mouseUp;
                if (callback != null)
                {
                    callback();
                }
            };
            _shapesCanvas.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                SmallProgramCallback callback = _mouseMove;
                Point position = e.GetPosition(_shapesCanvas);
                _mouseX = position.X;
                _mouseY = position.Y;
                if (callback != null)
                {
                    callback();
                }
            };
            _keyboardControl.KeyDown += delegate(object sender, KeyEventArgs e)
            {
                SmallProgramCallback temp = _keyDown;
                _lastKey = e.Key;
                if (temp != null)
                {
                    BeginInvoke(delegate
                    {
                        temp();
                    });
                }
                SmallProgramCallback temp2 = _textInput;
                if (temp2 != null)
                {
                    BeginInvoke(delegate
                    {
                        temp2();
                    });
                }
            };
            _keyboardControl.KeyUp += delegate(object sender, KeyEventArgs e)
            {
                InvokeHelper invokeDelegate = null;
                SmallProgramCallback temp = _keyUp;
                _lastKey = e.Key;
                if (temp != null)
                {
                    if (invokeDelegate == null)
                    {
                        invokeDelegate = delegate
                        {
                            temp();
                        };
                    }
                    BeginInvoke(invokeDelegate);
                }
            };
            */
        }

        internal class Pen
        {
            public SolidColorBrush Brush
            {
                get;
                set;
            }

            public double Thickness
            {
                get;
                set;
            }
        }
    }
}

